package com.atguigu.gulimall.product.service.impl;

import com.atguigu.common.constant.ProductConstant;
import com.atguigu.gulimall.product.entity.*;
import com.atguigu.gulimall.product.service.*;
import com.atguigu.gulimall.product.vo.AttrRespVo;
import com.atguigu.gulimall.product.vo.AttrVo;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;

import com.atguigu.gulimall.product.dao.AttrDao;
import org.springframework.transaction.annotation.Transactional;


@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {

    @Autowired
    AttrAttrgroupRelationService attrAttrgroupRelationService;

    @Autowired
    AttrGroupService attrGroupService;

    @Autowired
    CategoryService categoryService;

    @Autowired
    ProductAttrValueService productAttrValueService;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
                new QueryWrapper<AttrEntity>()
        );

        return new PageUtils(page);
    }

    /***
     *
     * @param attr AttVo 用于 响应前端发送的数据
     */
    @Transactional
    @Override
    public void saveAttrWithRelation(AttrVo attr) {
        AttrEntity attrEntity = new AttrEntity();
        BeanUtils.copyProperties(attr, attrEntity);
        this.save(attrEntity);
        // 保存数据到 中间表 只有 保存的属性是基本属性 才会去保存 属性与属性分组这张中间关联表
        if (attr.getAttrId() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode() && attr.getAttrGroupId() != null) {
            AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = new AttrAttrgroupRelationEntity();
            attrAttrgroupRelationEntity.setAttrId(attr.getAttrId());
            attrAttrgroupRelationEntity.setAttrGroupId(attr.getAttrGroupId());
            attrAttrgroupRelationService.save(attrAttrgroupRelationEntity);
        }

    }


    @Transactional
    @Override
    public PageUtils queryBaseAttr(Map<String, Object> params, long catelogId, String type) {
        // 这里查询分不同的情况  注意 数据库的 attr_type字段 为1时 查询规格参数 也就是基本属性
        QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<AttrEntity>().eq("attr_type",
                "base".equalsIgnoreCase(type) ? ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode() : ProductConstant.AttrEnum.ATTR_TYPE_SALE.getCode());

        if (catelogId != 0) {
            queryWrapper.eq("catelog_id", catelogId);
        }
        // 可能会进行模糊查询
        String key = (String) params.get("key");
        if (StringUtils.isNotEmpty(key)) {
            queryWrapper.eq("attr_id", key).or().like("attr_name", key);
        }
        IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
                queryWrapper
        );

        PageUtils pageUtils = new PageUtils(page);
        // 取出 当前查询的 分页所有数据 但是 没有 所属分组 和 所属分类
        List<AttrEntity> records = page.getRecords();
        List<AttrRespVo> respVos = records.stream().map((attrEntity) -> {
            AttrRespVo attrRespVo = new AttrRespVo();
            BeanUtils.copyProperties(attrEntity, attrRespVo);

            // 只有 查规格参数时 才 能设置分组 对于 销售属性没有分组
            if ("base".equalsIgnoreCase(type)) {
                // 从 属性与分组的关系 中间表中查出 所属分组的id
                AttrAttrgroupRelationEntity oneByAttrId = attrAttrgroupRelationService
                        .getOne(new QueryWrapper<AttrAttrgroupRelationEntity>()
                                .eq("attr_id", attrEntity.getAttrId()));
                // 把得到的 中间表数据 的 分组id 取出 查询 分组表
                if (oneByAttrId.getAttrId() != null && oneByAttrId.getAttrGroupId() != null) {
                    AttrGroupEntity attrGroupServiceById = attrGroupService.getById(oneByAttrId.getAttrGroupId());
                    attrRespVo.setGroupName(attrGroupServiceById.getAttrGroupName());
                }
            }

            CategoryEntity categoryById = categoryService.getById(attrEntity.getCatelogId());
            attrRespVo.setCatelogName(categoryById.getName());
            return attrRespVo;
        }).collect(Collectors.toList());
        pageUtils.setList(respVos);

        return pageUtils;
    }

    @Transactional
    @Override
    public AttrRespVo getMoreDetail(Long attrId) {
        AttrRespVo attrRespVo = new AttrRespVo();
        AttrEntity attrById = this.getById(attrId);
        BeanUtils.copyProperties(attrById, attrRespVo);

        // 查询属性分组id
        AttrAttrgroupRelationEntity attrGroup = attrAttrgroupRelationService.getOne(
                new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrId)
        );
        if (attrGroup != null && attrGroup.getAttrGroupId() != null) {
            attrRespVo.setAttrGroupId(attrGroup.getAttrGroupId());
        }
        Long[] parentsById = categoryService.getParentsById(attrById.getCatelogId());
        attrRespVo.setCatelogPath(parentsById);
        return attrRespVo;
    }

    /**
     * 更新属性  以及 关联表的冗余字段的更新
     *
     * @param attr
     */

    @Transactional
    @Override
    public void updateDetail(AttrVo attr) {
        AttrEntity attrEntity = new AttrEntity();
        BeanUtils.copyProperties(attr, attrEntity);
        // 修改 属性表
        this.updateById(attrEntity);
        // 先判断是否是 基本属性 如是 才会去更新这个基本属性所对应的中间关联表
        if (attr.getAttrId() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()) {
            // 修改属性关联表 时还得先判断  在这个 关联表中 是否有行数据 如果没有就 新增
            int count = attrAttrgroupRelationService.count(new QueryWrapper<AttrAttrgroupRelationEntity>()
                    .eq("attr_id", attr.getAttrId()));

            AttrAttrgroupRelationEntity relation = new AttrAttrgroupRelationEntity();
            relation.setAttrId(attr.getAttrId());
            relation.setAttrGroupId(attr.getAttrGroupId());
            if (count > 0) {
                attrAttrgroupRelationService.update(relation, new UpdateWrapper<AttrAttrgroupRelationEntity>()
                        .eq("attr_id", relation.getAttrId()));
            }

            attrAttrgroupRelationService.save(relation);
        }

    }

    @Override
    public List<AttrEntity> getAllRelations(Long attrgroupId) {
        // 先在中间表中 查询所有 符合的 行记录
        List<AttrAttrgroupRelationEntity> attrGroupRelations = attrAttrgroupRelationService
                .list(new QueryWrapper<AttrAttrgroupRelationEntity>()
                        .eq("attr_group_id", attrgroupId));

        // 流式遍历 该结合 去 属性表中查询 所对应的 行数据
        List<Long> attrIds = attrGroupRelations.stream().map((attrgroupRelation) -> {
            /*AttrEntity entity = this.getById(attrgroupRelation.getAttrId()); 会增大数据库访问的压力*/
            Long attrId = attrgroupRelation.getAttrId();
            return attrId;
        }).collect(Collectors.toList());


        if (attrIds == null || attrIds.size() == 0) {
            return null;
        }
        // 对于  this.listByIds(attrIds) 该方法 会去写 关于  in 的sql语句 前提 是 in对应的括号不能为空
        List<AttrEntity> attrEntities = (List<AttrEntity>) this.listByIds(attrIds);
        return attrEntities;
    }


    /**
     * 获取 当前 分类 的可以关联的 属性  TODO 1 该分类只能关联  该分类下 还未被其他分类关联的属性(基础属性)
     *
     * @param attrgroupId
     * @param params
     * @return
     */
    @Override
    public PageUtils getNoRelations(Long attrgroupId, Map<String, Object> params) {
        AttrGroupEntity attrGroupEntity = attrGroupService.getById(attrgroupId);
        List<AttrGroupEntity> catelogIds = attrGroupService.list(new QueryWrapper<AttrGroupEntity>()
                .eq("catelog_id", attrGroupEntity.getCatelogId()));

        // 取出所有的分组Id
        List<Long> attrGroupIds = catelogIds.stream().map((attrGroup) -> {
            Long attrGroupId = attrGroup.getAttrGroupId();
            return attrGroupId;
        }).collect(Collectors.toList());


        List<AttrAttrgroupRelationEntity> relationEntityList = attrAttrgroupRelationService.list(
                new QueryWrapper<AttrAttrgroupRelationEntity>().in("attr_group_id", attrGroupIds));

        QueryWrapper<AttrEntity> wrapper = new QueryWrapper<>();
        // 先判断 是否有模糊查询
        String key = (String) params.get("key");


        // 如果为空 表述 同 一分类下 在属性 分组关联表 没有数据  直接返回该分类下的所有的基本属性
        if (relationEntityList == null || relationEntityList.size() == 0) {
            wrapper
                    .eq("catelog_id", attrGroupEntity.getCatelogId())
                    .eq("attr_type", ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode());

            return getPageUtils(params, wrapper, key);
        }

        // 取出 所有的 属性 id
        List<Long> attrIds = relationEntityList.stream().map((relation) -> {
            Long attrId = relation.getAttrId();
            return attrId;
        }).collect(Collectors.toList());

        wrapper
                .eq("catelog_id", attrGroupEntity.getCatelogId())
                .eq("attr_type", ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode())
                .notIn("attr_id", attrIds);
        return getPageUtils(params, wrapper, key);
    }

    @Override
    public List<ProductAttrValueEntity> getSquBaseAttrById(Long spuId) {
        List<ProductAttrValueEntity> list = productAttrValueService.list(new QueryWrapper<ProductAttrValueEntity>()
                .eq("spu_id", spuId));
        return list;
    }

    /**
     * 商品上架 获取 相关 商品 会去检索的 属性
     * @param attrIds
     * @return
     */
    @Override
    public List<Long> getSearchAttrIds(List<Long> attrIds) {
        return baseMapper.getSearchAttrIds(attrIds);
    }


    private PageUtils getPageUtils(Map<String, Object> params, QueryWrapper<AttrEntity> wrapper, String key) {
        // 在拼接 sql时 尽量需要  把or 条件 置后
        if (StringUtils.isNotEmpty(key)) {
            wrapper.eq("attr_id", key).or().like("attr_name", key);
        }
        IPage<AttrEntity> page = this.page(new Query<AttrEntity>().getPage(params), wrapper);
        PageUtils pageUtils = new PageUtils(page);
        return pageUtils;
    }

}